#! /usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2020-04-04 09:24
# @Author : youngchaolin

print()

'''
1 名称空间，可以参考java中全局变量和局部变量，python中为全局名称空间和局部名称空间

全局名称空间：py程序运行时，会在内存中开辟一个空间，用于保存变量和变量的值之间的对应关系，
如果是函数，只是将函数名和函数的内容保存到这个名称空间，对里面的逻辑并不关心。

局部名称空间：当函数执行时，函数体里面会定义一些变量，这个时候就会开辟局部或者临时名称空间，
将这些变量和值的对应关系保存，当函数体执行完毕，这些临时名称空间下的变量和值的关系也就消失。

内置名称空间：python源码提供的一些内置的函数，如print，input等，保存在这个空间

2 加载顺序（加载到内存的顺序）
内置名称空间->全局名称空间->局部名称空间（函数执行时才开辟）

3 取值顺序（就近原则），单向不可逆
局部如果没有就从全局找，全局没有就去内置找


4 作用域
全局作用域：内置名称空间+全局名称空间
局部作用域：局部名称空间

'''

# 取值顺序
name='clyang'
def print_name():
    # 就近原则，print打印的是局部名称空间的name，局部如果没有就从全局找，全局没有就去内置找
    # 就近原则，也叫LEGB原则(local enclosing global builtin)
    name='messi'
    print(name)
print_name()

# 取值顺序 内置名称空间最后加载
def print_name_2():
    # 注释掉后，就先去全局找，全局没有，就去内置找
    # input='clyang'
    print(input)
print_name_2() # <built-in function input>

# 取值顺序 单向不可逆
def print_name_3():
    name='messi'
# 这里是先从全局找name，不会从局部里找，起点确定后，不会逆向回到局部再从新找，叫做单向不可逆
print_name_3()
print(name)

# 局部作用域可以引用全局作用域的变量，但是不能改变
date='周六'
def func():
    year=2012
    print(date)
func()
# 全局作用域不能引用局部作用域的变量year
# print(year)

# 局部作用域可以引用全局作用域的变量，但是不能改变
date='周六'
def func():
    # 注意，这不是改变，这是在局部新创建了变量并赋值
    date='周日'
    print(date)
func()
# 这里打印结果还是周日，说明全局作用域的变量没有改变
print(date)

# 继续测试 局部作用域是否可以修改全局作用域的变量
# count=1
# def revise():
#     # 报错 UnboundLocalError: local variable 'count' referenced before assignment
#     # 提示count这个局部变量在定义前就引用，是不允许的
#     count+=1
#     print(count)
# revise()

'''
局部作用域不能修改全局作用域中的变量，如上面的例子，当python解释器发现你准备对局部作用域中的某个变量进行修改时
它会默认你已经在局部作用域定义了这个局部变量，它就会去局部去找这个局部变量，发现并没有，就报错了
'''

# 以下也是局部作用域修改全局作用域变量的例子
# 当inner函数直接打印count，是没问题的，但是当需要修改时，这个count就是另外一个名称空间下的局部变量，也是需要先定义
def func():
    count=1 # 局部名称空间1
    def inner():
        # count+=1 # 局部名称空间2
        print(count)
    inner()
func()
